home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockBloggerService.js < prev    next >
Text File  |  2007-10-18  |  36KB  |  1,001 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16.  
  17. const ENABLE_DEBUG = true; // switch to turn off slow debug code for production
  18. function DEBUG(x) { if (ENABLE_DEBUG) debug("flockBloggerService: "+x+"\n"); }
  19.  
  20. const Cc = Components.classes;
  21. const Ci = Components.interfaces;
  22.  
  23. const BLOGGER_CID = Components.ID('{dec6797b-2155-4a79-9872-30f142074f0d}');
  24. const BLOGGER_CONTRACTID = '@flock.com/people/blogger;1';
  25. const BLOGGER_URL = "http://www.blogger.com/";
  26. const BLOGGER_FAVICON = "http://www.blogger.com/favicon.ico";
  27. const SERVICE_ENABLED_PREF          = "flock.service.blogger.enabled";
  28. const CATEGORY_COMPONENT_NAME       = "Blogger JS Component"
  29. const CATEGORY_ENTRY_NAME           = "blogger"
  30.  
  31. var loader = Cc['@mozilla.org/moz/jssubscript-loader;1'].getService(Ci.mozIJSSubScriptLoader);
  32.  
  33. loader.loadSubScript('chrome://browser/content/utilityOverlay.js');
  34. loader.loadSubScript("chrome://flock/content/blog/atom.js");
  35. loader.loadSubScript("chrome://flock/content/blog/blogBackendLib.js");
  36.  
  37. var gCompTK;
  38. function getCompTK() {
  39.   if (!gCompTK) {
  40.     gCompTK = Components.classes["@flock.com/singleton;1"]
  41.                         .getService(Components.interfaces.flockISingleton)
  42.                         .getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
  43.                         .wrappedJSObject;
  44.   }
  45.   return gCompTK;
  46. }
  47.  
  48. function flockBLService () {
  49.   var obs = Cc["@mozilla.org/observer-service;1"]
  50.                       .getService(Ci.nsIObserverService);
  51.   obs.addObserver(this, 'xpcom-shutdown', false);
  52.   this.status = Ci.flockIWebService.STATUS_UNKNOWN;
  53.  
  54.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  55.  
  56.   this.url = BLOGGER_URL;
  57.   this.status = Components.interfaces.flockIWebService.STATUS_UNKNOWN;
  58.  
  59.   this.supportsPostReplace = true;
  60.   this.mIsInitialized = false;
  61.  
  62.   this._ctk = {
  63.     interfaces: [
  64.       "nsISupports",
  65.       "nsIClassInfo",
  66.       "nsIObserver",
  67.       "nsISupportsCString",
  68.       "flockIWebService",
  69.       "flockIAuthenticateNewAccount",
  70.       "flockIManageableWebService",
  71.       "flockIBlogWebService"
  72.     ],
  73.     shortName: "blogger",
  74.     fullName: "Blogger",
  75.     description: "Google's Blogger.com Web Service",
  76.     favicon: BLOGGER_FAVICON,
  77.     CID: BLOGGER_CID,
  78.     contractID: BLOGGER_CONTRACTID,
  79.     accountClass: flockBLAccount
  80.   };
  81.   this._profiler = Cc["@flock.com/profiler;1"].getService(Ci.flockIProfiler);
  82.  
  83.   this.init();
  84. }
  85.  
  86. // Helpers
  87.  
  88. // For Google Auth (ClientLogin)
  89. flockBLService.prototype._parseError =
  90. function (aErrorString) {
  91.   var result = {};
  92.   var lines = aErrorString.split('\n');
  93.   for (i in lines) {
  94.     if (lines[i].length > 0) {
  95.       entry = lines[i].split('=');
  96.       result[entry[0]] = entry[1];
  97.     }
  98.   }
  99.  
  100.   return result;
  101. }
  102.  
  103.  
  104. // nsIObserver
  105. flockBLService.prototype.observe = function flockBLService_observe(subject, topic, state) {
  106.   switch (topic) {
  107.     case 'xpcom-shutdown':
  108.       var obs = Cc["@mozilla.org/observer-service;1"]
  109.         .getService(Ci.nsIObserverService);
  110.       obs.removeObserver(this, 'xpcom-shutdown');
  111.       return;
  112.   }
  113. }
  114.  
  115. // flockIWebService implementation
  116. flockBLService.prototype.addAccount =
  117. function flockBGService_addAccount(aUsername, aPassword, aListener)
  118. {
  119.   //DEBUG("{flockIWebService}.addAccount('"+aUsername+"', 'XXXXXXXX', ...)");
  120.   //DEBUG(" THIS FUNCTION IS DEPRECATED AND SHOULD BE REPLACED WITH A CALL TO addAccountById() !");
  121.   return this.addAccountById(aUsername, true, aListener);
  122. }
  123.  
  124. flockBLService.prototype.addAccountById =
  125. function flockBLService_addAccountById(aUsername, aIsTransient, aListener)
  126. {
  127.   var accountURN = this.urn+":"+aUsername;
  128.   var account = new this.faves_coop.Account(accountURN, {
  129.     name: aUsername,
  130.     serviceId: this.contractId,
  131.     service: this.blService,
  132.     accountId: aUsername,
  133.     favicon: this.icon,
  134.     URL: this.url,
  135.     isPollable: false,
  136.     isTransient: aIsTransient,
  137.     showInSidebar: false
  138.   });
  139.   this.faves_coop.accounts_root.children.addOnce(account);
  140.  
  141.   this.USER = accountURN;
  142.   var acct;
  143.  
  144.   // Add the blog account
  145.   blsvc = this;
  146.   var listener = {
  147.     onResult: function(aResult) {
  148.       var theBlog;
  149.       while (aResult.hasMoreElements()) {
  150.         theBlog = aResult.getNext();
  151.         theBlog.QueryInterface(Ci.flockIBlogAccount);
  152.         theCoopBlog = new blsvc.faves_coop.Blog(accountURN+":"+theBlog.title, {
  153.           name: theBlog.title,
  154.           title: theBlog.title,
  155.           blogid: theBlog.blogid,
  156.           URL: theBlog.URL,
  157.           apiLink: theBlog.apiLink,
  158.           authtoken: theBlog.authtoken
  159.         });
  160.         account.children.addOnce(theCoopBlog);
  161.       }
  162.       if (aListener) aListener.onSuccess(acct, "addAccount");
  163.     },
  164.     onFault: function(aError) {
  165.       notificationStream.destroy();
  166.       blsvc.faves_coop.accounts_root.children.remove(account);
  167.       account.destroy();
  168.       if (aListener) {
  169.         var error = Components.classes['@flock.com/error;1'].createInstance(Components.interfaces.flockIError);
  170.         error.serviceErrorString = aError;
  171.         aListener.onError(null, 'FAULT', error);
  172.       }
  173.     },
  174.     onError: function(aError) {
  175.       notificationStream.destroy();
  176.       blsvc.faves_coop.accounts_root.children.remove(account);
  177.       account.destroy();
  178.       if(aListener) {
  179.         aListener.onError(null, 'ERROR', aError);
  180.       }
  181.     }
  182.   }
  183.  
  184.   if (aUsername.match('@'))
  185.     this.getUsersBlogs(listener, 'http://beta.blogger.com/feeds/default/blogs');
  186.   else
  187.     this.getUsersBlogs(listener, 'http://www.blogger.com/feeds/default/blogs');
  188.  
  189.   acct = this.getAccount(accountURN);
  190.   return acct;
  191. }
  192.  
  193.  
  194. flockBLService.prototype.init =
  195. function ()
  196. {
  197.   DEBUG(".init()");
  198.  
  199.   // Prevent re-entry
  200.   if (this.mIsInitialized) return;
  201.   this.mIsInitialized = true;
  202.  
  203.   var evtID = this._profiler.profileEventStart("blogger-init");
  204.  
  205.   this.prefService = Components.classes["@mozilla.org/preferences-service;1"]
  206.                                .getService(Components.interfaces.nsIPrefBranch);
  207.   if ( this.prefService.getPrefType(SERVICE_ENABLED_PREF) &&
  208.        !this.prefService.getBoolPref(SERVICE_ENABLED_PREF) )
  209.   {
  210.     DEBUG("Pref "+SERVICE_ENABLED_PREF+" set to FALSE... not initializing.");
  211.     var catMgr = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  212.     catMgr.deleteCategoryEntry("wsm-startup", CATEGORY_COMPONENT_NAME, true);
  213.     catMgr.deleteCategoryEntry("flockWebService", CATEGORY_ENTRY_NAME, true);
  214.     return;
  215.   }
  216.  
  217.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  218.  
  219.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  220.   this.logger.init("blogger");
  221.  
  222.   this.faves_coop = Cc["@flock.com/singleton;1"]
  223.                     .getService(Ci.flockISingleton)
  224.                     .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  225.                     .wrappedJSObject;
  226.  
  227.   this.blService = new this.faves_coop.Service('urn:blogger:service');
  228.   this.blService.name = 'blogger';
  229.   this.blService.desc = 'The Blogger.com Service';
  230.   this.blService.logoutOption = false;
  231.   this.blService.domains = "google.com,blogger.com";
  232.   this.blService.serviceId = BLOGGER_CONTRACTID;
  233.  
  234.   this.urn = this.blService.id();
  235.   this.webDetective = this.acUtils.useWebDetective("blogger.xml");
  236.  
  237.   this._profiler.profileEventEnd(evtID, "");
  238. }
  239.  
  240.  
  241. flockBLService.prototype.refresh =
  242. function (aURN, aListener) {
  243.   throw Components.results.NS_ERROR_ABORT;
  244. }
  245.  
  246.  
  247. // BEGIN flockIBlogWebService interface
  248.  
  249. function atomListener(aListener){
  250.   this.listener = aListener;
  251.   this.logger = Cc['@flock.com/logger;1']
  252.     .createInstance(Ci.flockILogger);
  253.   this.logger.init("blog");
  254. }
  255.  
  256. atomListener.prototype = {
  257.   onResult: function(aResult) {
  258.     this.listener.onResult(aResult.atomid);
  259.   },
  260.   onError: function(error) {
  261.     this.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  262.     this.logger.error("ERROR "+error);
  263.     this.listener.onError(error);
  264.   },
  265.   onFault: function(error) {
  266.     this.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  267.     this.logger.error("FAULTAA "+error);
  268.     this.listener.onFault(error);
  269.   }
  270. }
  271.  
  272. flockBLService.prototype.doAuthRequest = function(listener, method, url, body, processor) {
  273.   var inst = this;
  274.   this._req = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  275.   this._req.onreadystatechange = function (aEvt) {
  276.     inst.logger.info("<<<<<<<<<< Google API: SERVER TO FLOCK");
  277.     inst.logger.info("Request readyState: "+inst._req.readyState);
  278.     if(inst._req.readyState == 4) {
  279.       inst.logger.info("Request status: "+inst._req.status);
  280.       inst.logger.debug("\nRESPONSE\n" + inst._req.responseText);
  281.       try {
  282.         if(inst._req.status == 200 || inst._req.status == 201 || inst._req.status == 205) {
  283.         try {
  284.             processor(listener, inst);
  285.           }
  286.           catch(e) {
  287.             // listener.onError(inst.ERROR_PARSER);
  288.             inst.logger.error(e + " " + e.lineNumber);
  289.           }
  290.         }
  291.         else {
  292.           var faultString; //: "Make sure that are not trying to blog really weird html, and note the following kind user:\n\n",
  293.           // };
  294.           // faultString = inst._req.responseText;
  295.           inst.logger.error("Error: "+inst._req.responseText);
  296.           // listener.onFault(faultString);
  297.           var answer = inst._parseError(inst._req.responseText);
  298.           var error = Cc['@flock.com/error;1'].createInstance(Ci.flockIError);
  299.           error.serviceErrorString = answer["Error"];
  300.           inst.logger.error("***"+error.serviceErrorString+"***");
  301.           switch (error.serviceErrorString) {
  302.             case "BadAuthentication": // Invalid login/pass
  303.               error.errorCode = Ci.flockIError.BLOG_INVALID_AUTH;
  304.               error.errorString = "Bad authentication";
  305.               break;
  306.             case "CaptchaRequired":
  307.               error.errorCode = Ci.flockIError.BLOG_CAPTCHA_REQUIRED;
  308.               error.errorString = "Captcha Required";
  309.               break;
  310.              case "NotVerified":
  311.               error.errorCode = Ci.flockIError.BLOG_NOT_VERIFIED;
  312.               error.errorString = "Email Not Verified";
  313.               break;           
  314.             default: // Unknown error code
  315.               error.errorCode = Ci.flockIError.BLOG_UNKNOWN;
  316.               error.errorString = "Unknown Error";
  317.           }
  318.           listener.onError(error);
  319.         }
  320.       } catch(e) {
  321.         inst.logger.error(e + " " + e.fileName + " " + e.lineNumber);
  322.         listener.onError(inst.ERROR_PARSER);
  323.       }
  324.     }
  325.   };
  326.   rval = this._req.open(method, url, true);
  327.   this._req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  328.   this.logger.info(">>>>>>>>>> Google API: FLOCK TO SERVER");
  329.   this.logger.info("\nSENDING\n" + body);
  330.   this.logger.info("\nTO\n" + method + " @ " + url);
  331.   rval = this._req.send(body);
  332. }
  333.  
  334. flockBLService.prototype.doRequest = function(listener, method, url, body, authToken, processor) {
  335.   var inst = this;
  336.   this._req = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  337.   this._req.onreadystatechange = function (aEvt) {
  338.     inst.logger.info("<<<<<<<<<< Google API: SERVER TO FLOCK");
  339.     debug("<<<<<<<<<< Google API: SERVER TO FLOCK\n");
  340.     inst.logger.info("Request readyState: "+inst._req.readyState);
  341.     debug("Request readyState: "+inst._req.readyState+"\n");
  342.     if (inst._req.readyState == 4) {
  343. //      inst.logger.info("Request status: "+inst._req.status);
  344. //      debug("Request status: "+inst._req.status+"\n");
  345.       inst.logger.info("\nRESPONSE\n" + inst._req.responseText);
  346.       debug("\nRESPONSE\n" + inst._req.responseText+"\n");
  347.       try {
  348.         if (inst._req.status == 200 || inst._req.status == 201 || inst._req.status == 205) {
  349.           try {
  350.             processor(listener, inst, authToken);
  351.           }
  352.           catch(e) {
  353.             // listener.onError(inst.ERROR_PARSER);
  354.             inst.logger.error(e + " " + e.lineNumber);
  355.           }
  356.         }
  357.         else {
  358.           var faultString; //: "Make sure that are not trying to blog really weird html, and note the following kind user:\n\n",
  359.           faultString = inst._req.responseText;
  360.           inst.logger.error(faultString+"\n");
  361.           listener.onFault(faultString);
  362.         }
  363.       } catch(e) {
  364.         inst.logger.error(e + " " + e.fileName + " " + e.lineNumber);
  365.         listener.onError(inst.ERROR_PARSER);
  366.       }
  367.     }
  368.   };
  369.   rval = this._req.open(method, url, true);
  370.   this._req.setRequestHeader("Authorization", "GoogleLogin auth="+authToken);
  371.   this.logger.info(">>>>>>>>>> Google API: FLOCK TO SERVER");
  372.   debug(">>>>>>>>>> Google API: FLOCK TO SERVER\n");
  373.   this.logger.info("\nSENDING\n" + body);
  374.   debug("\nSENDING\n" + body+"\n");
  375.   this.logger.info("\nTO\n" + method + " @ " + url);
  376.   debug("\nTO\n" + method + " @ " + url+"\n");
  377.   rval = this._req.send(body);
  378. }
  379.  
  380. flockBLService.prototype.parseUsersBlogs = function(listener, inst, authToken) {
  381.   try {
  382.     var result = new Array();
  383.     var dom = inst._req.responseXML;
  384.  
  385.     var domEntries = dom.getElementsByTagName("entry");
  386.     for (i=0; i<domEntries.length; i++) {
  387.       domEntry = domEntries[i];
  388.       title = domEntry.getElementsByTagName("title")[0].textContent;
  389.       var newAccount = new BlogAccount(title);
  390.       newAccount.api = this.shortName;
  391.       newAccount.authtoken = authToken;
  392.       var links = domEntry.getElementsByTagName("link");
  393.       for (j=0; j<links.length; j++) {
  394.         var link = links[j]
  395.         switch (link.getAttribute("rel")) {
  396.           case "alternate":
  397.             newAccount.URL = link.getAttribute("href");
  398.             break;
  399.           case "http://schemas.google.com/g/2005#post":
  400.             newAccount.apiLink = link.getAttribute("href");
  401.             break;
  402.         }
  403.       }
  404.       result.push(newAccount);
  405.     }
  406.     debug("Found "+ result.length +" blogs\n");
  407.     listener.onResult(new simpleEnumerator(result));
  408.   }
  409.   catch(e) {
  410.     var logger = Cc['@flock.com/logger;1']
  411.        .createInstance(Ci.flockILogger);
  412.     logger.init("blog");
  413.     logger.error(e + " " + e.lineNumber);
  414.     listener.onError(e + " " + e.lineNumber);
  415.   }
  416. }
  417.  
  418. flockBLService.prototype.parseRecentPosts = function(listener, inst) {
  419.   var getNamedChild = function(node, name) {
  420.     for(var i=0;i<node.childNodes.length;++i) {
  421.       if(node.childNodes[i].nodeName==name)
  422.         return node.childNodes[i];
  423.     }
  424.     return null;
  425.   };
  426.  
  427.   var result = new Array();
  428.  
  429.   debug(inst._req.responseText);
  430.  
  431.   var dom = inst._req.responseXML;
  432.   var entries = dom.getElementsByTagName("entry");
  433.   for(var i=0;i<entries.length;++i) {
  434.     try {
  435.       var entry_n = entries[i];
  436.       var post = new BlogPost();
  437.       post.title = getNamedChild(entry_n, "title").firstChild.nodeValue;
  438.       post.issued = getNamedChild(entry_n, "published").firstChild.nodeValue;
  439.  
  440.       var atomid_n = entry_n.getElementsByTagName("id")[0];
  441.       post.postid = "";
  442.       if(atomid_n) post.postid = atomid_n.firstChild.nodeValue; //.split('/').pop();
  443.  
  444.       var link_n = null;
  445.       for(var j=0;j<entry_n.childNodes.length;++j) {
  446.         if(entry_n.childNodes[j].nodeName=="link") {
  447.           var tmp = entry_n.childNodes[j];
  448.           if(tmp.getAttribute("rel").match(/edit/)) {
  449.             link_n = tmp;
  450.           }
  451.           if(tmp.getAttribute("rel").match(/alternate/)) {
  452.             permalink_n = tmp;
  453.           }
  454.         }
  455.       }
  456.  
  457.       var permaLink = permalink_n.getAttribute("href");
  458.       var href = link_n.getAttribute("href");
  459.       // href.match(/.+\/(.+)/);
  460.       post.editURI = href; // RegExp.$1;
  461.       debug("post.editURI: "+post.editURI+"\n");
  462.  
  463.       result.push(post);
  464.     }
  465.     catch(e) {
  466.       var logger = Cc['@flock.com/logger;1']
  467.         .createInstance(Ci.flockILogger);
  468.       logger.error(e + " " + e.lineNumber + " " + e.fileName);
  469.     }
  470.   }
  471.   listener.onResult(new simpleEnumerator(result));
  472. }
  473.  
  474. flockBLService.prototype.newPost =
  475. function(aListener, aBlogId, aPost, aPublish, aNotifications)
  476. {
  477.   var svc = this;
  478.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  479.   var account = gBlogService.getAccount(aBlogId);
  480.  
  481.   var listener = {
  482.     onResult: function(aResult) {
  483.       aListener.onResult(aResult.atomid);
  484.     },
  485.     onError: function(error) {
  486.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  487.       svc.logger.error("ERROR " + error.serviceErrorString);
  488.       aListener.onError(error);
  489.     },
  490.     onFault: function(error) {
  491.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  492.       svc.logger.error("FAULTXX "+error.serviceErrorString);
  493.       if (error.serviceErrorCode == 401) {
  494.         // The token is bad or missing, let's get a brand new one
  495.         var parseAuthToken = function (listener, inst){
  496.           var response = inst._req.responseText;
  497.           response.match(/Auth=(.+)/);
  498.           var token = RegExp.$1;
  499.           var coopBlog = svc.faves_coop.get(aBlogId);
  500.           coopBlog.authtoken = token;
  501.           svc.newPost(aListener, aBlogId, aPost, aPublish, aNotifications);
  502.         };
  503.         var body = 'Email='+encodeURIComponent(account.username)+'&Passwd='+encodeURIComponent(account.password)+'&service=blogger&source=FlockInc-Flock-0.8';
  504.         svc.doAuthRequest(listener, "POST", "https://www.google.com/accounts/ClientLogin", body, parseAuthToken);
  505.       }
  506.       else
  507.         aListener.onFault(error);
  508.     }
  509.   }
  510.  
  511.   var atomEntry = {
  512.     title: aPost.title,
  513.     content: aPost.description
  514.   };
  515.   var labels = new Array();
  516.   if (aPost.tags)
  517.     while (aPost.tags.hasMore()) {
  518.       var label = aPost.tags.getNext();
  519.       if (label.length > 0)
  520.         labels.push(label);
  521.     }
  522.   if (labels.length > 0)
  523.     atomEntry.categories = labels;
  524.   // Hack because Blogger announce www but takes beta
  525.   var url = account.apiLink.replace('www', 'beta');
  526.   flockAtomPost (listener, url, atomEntry, account.authtoken);
  527. }
  528.  
  529. flockBLService.prototype.editPost =
  530. function(aListener, aBlogId, aPost, aPublish, aNotifications)
  531. {
  532.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  533.   var account = gBlogService.getAccount(aBlogId);
  534.  
  535.   if (account.username.match('@')) { // Blogger beta
  536.     var listener = new atomListener(aListener);
  537.     var account = gBlogService.getAccount(aBlogId);
  538.  
  539.     var atomEntry = {
  540.       id: aPost.postid,
  541.       title: aPost.title,
  542.       content: aPost.description,
  543.       issued: aPost.issued
  544.     };
  545.     var labels = new Array();
  546.     while (aPost.tags.hasMore())
  547.       labels.push(aPost.tags.getNext());
  548.     if (labels.length > 0)
  549.       atomEntry.categories = labels;
  550.     // Hack because Blogger announce www but takes beta
  551.     var url = aPost.editURI.replace('www', 'beta');
  552.     flockAtomEdit (listener, url, atomEntry, account.authtoken);
  553.   }
  554.   else {
  555.     var atomAPI = Cc['@flock.com/blog/service/atom;1'].getService (Ci.flockIBlogWebService);
  556.     atomAPI.editPost(aListener, aBlogId, aPost, aPublish, aNotifications);
  557.   }
  558. }
  559.  
  560. flockBLService.prototype.deletePost =
  561. function(aListener, aBlogId, aPostid)
  562. {
  563.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  564.   var account = gBlogService.getAccount(aBlogId);
  565.  
  566.   if (account.username.match('@')) { // Blogger beta
  567.     var handleDelete = function(listener, inst) {
  568.       listener.onResult(1);
  569.     }
  570.  
  571.     var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  572.     var account = gBlogService.getAccount(aBlogId);
  573.     var url = account.apiLink;
  574.     url += "/" + aPostid;
  575.     // if(aEditURI) url = aEditURI;
  576.     this.doRequest(aListener,"DELETE", url, null, account.authtoken, handleDelete);
  577.   }
  578.   else {
  579.     var atomAPI = Cc['@flock.com/blog/service/atom;1'].getService (Ci.flockIBlogWebService);
  580.     atomAPI.deletePost(aListener, aBlogId, aPostid);
  581.   }
  582. }
  583.  
  584.  
  585. flockBLService.prototype._getUsersBlogs =
  586. function(aListener, aAPILink)
  587. {
  588.   var inst = this;
  589.   this._req = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  590.   this._req.onreadystatechange = function (aEvt) {
  591.     inst.logger.info("<<<<<<<<<< Blogger: SERVER TO FLOCK");
  592.     inst.logger.info("Request readyState: "+inst._req.readyState);
  593.     if(inst._req.readyState == 4) {
  594.       inst.logger.info("Request status: "+inst._req.status);
  595.       inst.logger.info("\nRESPONSE\n" + inst._req.responseText);
  596.       //try {
  597.         if(inst._req.status == 200 || inst._req.status == 201 || inst._req.status == 205) {
  598.         //try {
  599.           var result = new Array();
  600.           var dom = inst._req.responseXML;
  601.  
  602.           if (!dom) {
  603.             debug("Problem: "+inst._req.responseText+"\n");
  604.             listener.onError(null);
  605.           }
  606.  
  607.           var domEntries = dom.getElementsByTagName("entry");
  608.           for (i=0; i<domEntries.length; i++) {
  609.             domEntry = domEntries[i];
  610.             title = domEntry.getElementsByTagName("title")[0].textContent;
  611.             var newAccount = new BlogAccount(title);
  612.             newAccount.api = this.shortName;
  613.             var links = domEntry.getElementsByTagName("link");
  614.             for (j=0; j<links.length; j++) {
  615.               var link = links[j]
  616.               switch (link.getAttribute("rel")) {
  617.                 case "alternate":
  618.                   newAccount.URL = link.getAttribute("href");
  619.                   break;
  620.                 case "http://schemas.google.com/g/2005#post":
  621.                   newAccount.apiLink = link.getAttribute("href");
  622.                   break;
  623.               }
  624.             }
  625.             result.push(newAccount);
  626.           }
  627.           debug("Found "+ result.length +" blogs\n");
  628.           aListener.onResult(new simpleEnumerator(result));
  629.         //}
  630.         //catch(e) {
  631.           // listener.onError(inst.ERROR_PARSER);
  632.           //inst.logger.error(e + " " + e.lineNumber+"\n");
  633.         //}
  634.       }
  635.       else {
  636.         var faultString; //: "Make sure that are not trying to blog really weird html, and note the following kind user:\n\n",
  637.         faultString = inst._req.responseText;
  638.         //faultString += inst._req;
  639.         inst.logger.error(faultString);
  640.         aListener.onFault(faultString);
  641.       }
  642.     //} catch(e) {
  643.     //  inst.logger.error(e + " " + e.fileName + " " + e.lineNumber + "\n");
  644.     //  listener.onError(inst.ERROR_PARSER);
  645.     //  }
  646.     }
  647.   };
  648.  
  649.   var username = this.faves_coop.get(this.USER).name;
  650.   debug("USER: "+username+"\n");
  651.   var pw = this.acUtils.getPassword(this.urn+':'+username);
  652.  
  653.   rval = this._req.open("GET", aAPILink, true, username, pw.password);
  654.   rval = this._req.send(null);
  655. }
  656.  
  657. flockBLService.prototype._getUsersBlogsBeta = function (aListener, aUrl){
  658.   debug("getUsersBlog... "+aUrl+"\n");
  659.   var inst = this;
  660.  
  661.   var parseAuthToken = function (listener, inst){
  662.     var response = inst._req.responseText;
  663.     response.match(/Auth=(.+)/);
  664.     var token = RegExp.$1;
  665.     debug("Found the token: "+token+"\n");
  666.     listener.onResult(token);
  667.   };
  668.  
  669.   var listener = {
  670.     onResult: function(aToken) {
  671.       inst.doRequest(aListener, "GET", aUrl, null, aToken, inst.parseUsersBlogs);
  672.     },
  673.     onError: function(aError) {
  674.       aListener.onError(aError);
  675.     },
  676.     onFault: function(aError) {
  677.       aListener.onError(aError);
  678.     }
  679.   }
  680.  
  681.   var username = this.faves_coop.get(this.USER).name;
  682.   debug("USER: "+username+"\n");
  683.   var pw = this.acUtils.getPassword(this.urn+':'+username);
  684.  
  685.   var body = 'Email='+encodeURIComponent(username)+'&Passwd='+encodeURIComponent(pw.password)+'&service=blogger&source=FlockInc-Flock-0.8';
  686.   this.doAuthRequest(listener, "POST", "https://www.google.com/accounts/ClientLogin", body, parseAuthToken);
  687. }
  688.  
  689. flockBLService.prototype.getUsersBlogs =
  690. function(aListener, aAPILink)
  691. {
  692.   var username = this.faves_coop.get(this.USER).name;
  693.   if (username.match('@'))
  694.     this._getUsersBlogsBeta(aListener, aAPILink);
  695.   else
  696.     this._getUsersBlogs(aListener, aAPILink);
  697. }
  698.  
  699. flockBLService.prototype.getRecentPosts = function(aListener, aBlogId, aNumber){
  700.   var gBlogService = Cc['@flock.com/flock-blog;1'].getService(Ci['flockIBlogService']);
  701.   var account = gBlogService.getAccount(aBlogId);
  702.  
  703.   var url = account.apiLink;
  704.   url.match(/(.+\/)(.+)/);
  705.   if (RegExp.$2 == "post") {
  706.     url = RegExp.$1 + "feed";
  707.   }
  708.   
  709.   var listener = {
  710.     onResult: function(aResult) {
  711.       aListener.onResult(aResult);
  712.     },
  713.     onError: function(error) {
  714.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  715.       svc.logger.error("ERROR " + error.serviceErrorString);
  716.       aListener.onError(error);
  717.     },
  718.     onFault: function(error) {
  719.       svc.logger.error("<<<<<<<<<< Google API: SERVER TO FLOCK");
  720.       svc.logger.error("FAULTXX "+error.serviceErrorString);
  721.       if (error.serviceErrorCode == 401) {
  722.         // The token is bad or missing, let's get a brand new one
  723.         var parseAuthToken = function (listener, inst){
  724.           var response = inst._req.responseText;
  725.           response.match(/Auth=(.+)/);
  726.           var token = RegExp.$1;
  727.           var coopBlog = svc.faves_coop.get(aBlogId);
  728.           coopBlog.authtoken = token;
  729.           inst.doRequest(listener, "GET", url, null, token, inst.parseRecentPosts);
  730.         };
  731.         var body = 'Email='+encodeURIComponent(account.username)+'&Passwd='+encodeURIComponent(account.password)+'&service=blogger&source=FlockInc-Flock-0.8';
  732.         inst.doAuthRequest(listener, "POST", "https://www.google.com/accounts/ClientLogin", body, parseAuthToken);
  733.       }
  734.       else
  735.         aListener.onFault(error);
  736.     }
  737.   }
  738.   
  739.   this.doRequest(listener, "GET", url, null, account.authtoken, this.parseRecentPosts);
  740. }
  741.  
  742. flockBLService.prototype.getCategoryList = function(aListener, aBlogId){
  743.   aListener.onResult(null);
  744. }
  745.  
  746. // END flockIBlogWebService interface
  747.  
  748.  
  749. // BEGIN flockIManageableWebService interface
  750. flockBLService.prototype.docRepresentsSuccessfulLogin =
  751. function flockBLService_docRepresentsSuccessfulLogin(aDocument)
  752. {
  753.   this.logger.debug("{flockIManageableWebService}.docRepresentsSuccessfulLogin(aDocument)");
  754.   aDocument.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
  755.   return this.webDetective.detect("blogger", "loggedin", aDocument, null);
  756. }
  757.  
  758. flockBLService.prototype.ownsDocument =
  759. function flockBLService_ownsDocument(aDocument)
  760. {
  761.   this.logger.debug("{flockIManageableWebService}.ownsDocument(aDocument)");
  762.   aDocument.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
  763.   var ios = Components.classes["@mozilla.org/network/io-service;1"]
  764.                       .getService(Components.interfaces.nsIIOService);
  765.   var uri = ios.newURI(aDocument.URL, null, null);
  766.   if ((uri.host == "blogger.com") || (uri.host.indexOf(".blogger.com") > 0)) {
  767.     return true;
  768.   }
  769.   if (uri.host.indexOf("google.com") > -1) {// Login page for Blogger Beta
  770.     return true;
  771.   }
  772.   return false;
  773. }
  774.  
  775. flockBLService.prototype.updateAccountStatusFromDocument =
  776. function flockBLService_updateAccountStatusFromDocument(aDocument)
  777. {
  778.   this.logger.debug("{flockIManageableWebService}.updateAccountStatusFromDocument(aDocument)");
  779.   if (this.ownsDocument(aDocument)) {
  780.     if (this.docRepresentsSuccessfulLogin(aDocument)) {
  781.       var accountID = this.getAccountIDFromDocument(aDocument);
  782.       
  783.       var results = Components.classes["@mozilla.org/hash-property-bag;1"].createInstance(Components.interfaces.nsIWritablePropertyBag2);
  784.  
  785.       var avatarURL;
  786.       if(this.webDetective.detect("blogger", "accountinfo", aDocument, results)) {
  787.         try {
  788.           avatarURL = results.getPropertyAsAString("avatarURL");
  789.         } catch(e) {
  790.           // No avatar found
  791.         }
  792.       }
  793.  
  794.       var acctURN = this.acUtils.getAccountURNById(this.urn, accountID);
  795.       var acct = this.faves_coop.get(acctURN);
  796.       if (acct) {
  797.         acct.avatar = avatarURL;
  798.  
  799.         var accounts = this.faves_coop.Account.find({serviceId: BLOGGER_CONTRACTID});
  800.         for (var i = 0; i < accounts.length; i++) {
  801.           if (accounts[i].id() == acctURN) {
  802.             accounts[i].isAuthenticated = true;
  803.           } else {
  804.             accounts[i].isAuthenticated = false;
  805.           }
  806.         }
  807.       }
  808.     } else {
  809.       var login = aDocument.getElementById("Login");
  810.       if (login) {
  811.         this.acUtils.markAllAccountsAsLoggedOut(BLOGGER_CONTRACTID);
  812.       }
  813.     }
  814.   }
  815. }
  816.  
  817. flockBLService.prototype.logout = function() {
  818.   this.logger.info("{flockIWebServiceService}.logout()");
  819.   var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"]
  820.                                 .getService(Components.interfaces.nsICookieManager);
  821.   cookieManager.remove(".blogger.com", "blogger_SID", "/", false);
  822.   cookieManager.remove(".blogger.com", "B2I", "/", false);
  823.   cookieManager.remove(".blogger.com", "ServerID", "/", false);
  824.   cookieManager.remove(".blogger.com", "S", "/", false);
  825.   cookieManager.remove(".blogger.com", "__utma", "/", false);
  826.   cookieManager.remove(".blogger.com", "__utmb", "/", false);
  827.   cookieManager.remove(".blogger.com", "__utmc", "/", false);
  828.   cookieManager.remove(".blogger.com", "__utmz", "/", false);
  829.   cookieManager.remove(".blogger.com", "NSC_cmphhfs-fyu", "/", false);
  830.   cookieManager.remove("blogger.com", "NSC_cmphhfs-fyu", "/", false);
  831.   cookieManager.remove("www.blogger.com", "NSC_cmphhfs-fyu", "/", false);
  832.   cookieManager.remove("www.blogger.com", "JSESSIONID", "/", false);
  833.   cookieManager.remove(".www2.blogger.com", "__utma", "/", false);
  834.   cookieManager.remove(".www2.blogger.com", "__utmb", "/", false);
  835.   cookieManager.remove(".www2.blogger.com", "__utmc", "/", false);
  836.   cookieManager.remove(".www2.blogger.com", "__utmz", "/", false);
  837.   cookieManager.remove("www2.blogger.com", "S", "/", false);
  838.   cookieManager.remove("www.google.com", "LSID", "/accounts", false);
  839. }
  840.  
  841.  
  842. // END flockIManageableWebService interface
  843.  
  844.  
  845.  
  846. // ================================================
  847. // ========== BEGIN XPCOM Module support ==========
  848. // ================================================
  849.  
  850. function createModule(aParams) {
  851.   var Cc = Components.classes;
  852.   var Ci = Components.interfaces;
  853.   var Cr = Components.results;
  854.   return {
  855.     registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
  856.       aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  857.       aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
  858.                                         aParams.contractID, aFileSpec,
  859.                                         aLocation, aType );
  860.       var catMgr = Cc["@mozilla.org/categorymanager;1"]
  861.         .getService(Ci.nsICategoryManager);
  862.       if (!aParams.categories) { aParams.categories = []; }
  863.       for (var i = 0; i < aParams.categories.length; i++) {
  864.         var cat = aParams.categories[i];
  865.         catMgr.addCategoryEntry( cat.category, cat.entry,
  866.                                  cat.value, true, true );
  867.       }
  868.     },
  869.     getClassObject: function (aCompMgr, aCID, aIID) {
  870.       if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
  871.       if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
  872.       return { // Factory
  873.         createInstance: function (aOuter, aIID) {
  874.           if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
  875.           var comp = new aParams.componentClass();
  876.           if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
  877.           return comp.QueryInterface(aIID);
  878.         }
  879.       };
  880.     },
  881.     canUnload: function (aCompMgr) { return true; }
  882.   };
  883. }
  884.  
  885. // NS Module entrypoint
  886. function NSGetModule(aCompMgr, aFileSpec) {
  887.   return createModule({
  888.     componentClass: flockBLService,
  889.     CID: BLOGGER_CID,
  890.     contractID: BLOGGER_CONTRACTID,
  891.     componentName: CATEGORY_COMPONENT_NAME,
  892.     implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); },
  893.     categories: [
  894.       { category: "wsm-startup", entry: CATEGORY_COMPONENT_NAME, value: BLOGGER_CONTRACTID },
  895.       { category: "flockWebService", entry: CATEGORY_ENTRY_NAME, value: BLOGGER_CONTRACTID }
  896.     ]
  897.   });
  898. }
  899.  
  900. // ========== END XPCOM Module support ==========
  901.  
  902.  
  903. /* ********** Account Class ********** */
  904.  
  905. function flockBLAccount() {
  906.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  907.   this.logger.init("bloggerAccount");
  908.  
  909.   this.faves_coop = Cc["@flock.com/singleton;1"]
  910.                     .getService(Ci.flockISingleton)
  911.                     .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  912.                     .wrappedJSObject;
  913.  
  914.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  915.  
  916.   this.service = Cc[BLOGGER_CONTRACTID].getService(Ci.flockIBlogWebService)
  917. }
  918.  
  919. // nsISupports implementation
  920. flockBLAccount.prototype.QueryInterface = function(iid) {
  921.   if (!iid.equals(Ci.nsISupports) &&
  922.     !iid.equals(Ci.flockIWebServiceAccount) &&
  923.     !iid.equals(Ci.flockIBlogWebServiceAccount))
  924.   {
  925.     throw Components.results.NS_ERROR_NO_INTERFACE;
  926.   }
  927.   return this;
  928. }
  929.  
  930. // flockIWebServiceAccount implementation
  931. flockBLAccount.prototype.login = function(listener) {
  932.   this.logger.info("{flockIWebServiceAccount}.login()");
  933.   if (listener) {
  934.     listener.onSuccess(this, "login");
  935.   }
  936. }
  937. flockBLAccount.prototype.logout = function(listener) {
  938.   this.logger.info("{flockIWebServiceAccount}.logout()");
  939.   var c_acct = this.faves_coop.get(this.urn);
  940.   if (c_acct.isAuthenticated) {
  941.     c_acct.isAuthenticated = false;
  942.     var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"]
  943.                                   .getService(Components.interfaces.nsICookieManager);
  944.     cookieManager.remove(".blogger.com", "B2I", "/", false);
  945.     cookieManager.remove(".blogger.com", "blogger_SID", "/", false);
  946.     cookieManager.remove(".blogger.com", "ServerID", "/", false);
  947.     cookieManager.remove(".blogger.com", "__utma", "/", false);
  948.     cookieManager.remove(".blogger.com", "__utmb", "/", false);
  949.     cookieManager.remove(".blogger.com", "__utmc", "/", false);
  950.     cookieManager.remove(".blogger.com", "__utmz", "/", false);
  951.     cookieManager.remove(".blogger.com", "NSC_cmphhfs-fyu", "/", false);
  952.     cookieManager.remove("blogger.com", "NSC_cmphhfs-fyu", "/", false);
  953.     cookieManager.remove("www.blogger.com", "NSC_cmphhfs-fyu", "/", false);
  954.     cookieManager.remove("www.blogger.com", "JSESSIONID", "/", false);
  955.     cookieManager.remove(".www2.blogger.com", "__utma", "/", false);
  956.     cookieManager.remove(".www2.blogger.com", "__utmb", "/", false);
  957.     cookieManager.remove(".www2.blogger.com", "__utmc", "/", false);
  958.     cookieManager.remove(".www2.blogger.com", "__utmz", "/", false);
  959.     cookieManager.remove("www2.blogger.com", "S", "/", false);
  960.     cookieManager.remove("www.google.com", "LSID", "/accounts", false);
  961.   }
  962.   if (listener) {
  963.     listener.onSuccess(this, "logout");
  964.   }
  965. }
  966. flockBLAccount.prototype.activate = function(aListener) {
  967.   this.logger.info("{flockIWebServiceAccount}.activate()");
  968. }
  969. flockBLAccount.prototype.deactivate = function() {
  970.   this.logger.info("{flockIWebServiceAccount}.deactivate()");
  971. }
  972. flockBLAccount.prototype.keep = function() {
  973.   var c_acct = this.faves_coop.get(this.urn);
  974.   c_acct.isTransient = false;
  975.   this.acUtils.makeTempPasswordPermanent(this.service.urn+':'+c_acct.accountId);
  976. }
  977. flockBLAccount.prototype.remove = function() {
  978.   this.service.removeAccount(this.urn);
  979. }
  980.  
  981. // flockIBlogWebServiceAccount implementation
  982. flockBLAccount.prototype.getBlogs = function() {
  983.   this.logger.info("{flockIBlogWebServiceAccount}.getBlogs()");
  984.   var blogsEnum = {
  985.     QueryInterface : function(iid) {
  986.       if (!iid.equals(Ci.nsISupports) &&
  987.           !iid.equals(Ci.nsISimpleEnumerator))
  988.       {
  989.         throw Components.results.NS_ERROR_NO_INTERFACE;
  990.       }
  991.       return this;
  992.     },
  993.     hasMoreElements : function() {
  994.       return false;
  995.     },
  996.     getNext : function() {
  997.     }
  998.   };
  999.   return blogsEnum;
  1000. }
  1001.